package com.filetransfer.filemanager.controller;

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

import org.apache.log4j.Logger;

import com.filetransfer.domain.ChunkData;
import com.filetransfer.domain.FileInfo;
import com.filetransfer.domain.FileInfoHolder;
import com.filetransfer.domain.FileTransferMessage;
import com.filetransfer.domain.Messages;

public class ChunkUploaderThread extends Thread {

	private int port;
	private boolean doService = true;
	private ServerSocket providerSocket;
	private Socket connection = null;
	private ObjectOutputStream out;
	private ObjectInputStream in;
	private FileInfoHolder holder;

	private static Logger logger = Logger.getLogger(ChunkUploaderThread.class);

	
	public ChunkUploaderThread(int aport, FileInfoHolder aHolder){
		port = aport;
		holder = aHolder;
	}
	
	public int getPort() {
		return port;
	}



	public void setPort(int port) {
		this.port = port;
	}



	public boolean isDoService() {
		return doService;
	}



	public void setDoService(boolean doService) {
		this.doService = doService;
	}

	


	/**
	 * 
	 */
	public void run(){
		
		try{
			while(doService){
				//1. creating a server socket
				providerSocket = new ServerSocket(port, 10);
				//2. Wait for connection
				System.out.println("Waiting for connection");
				connection = providerSocket.accept();

				System.out.println("Connection received from " + connection.getInetAddress().getHostName());
				//3. get Input and Output streams
				out = new ObjectOutputStream(connection.getOutputStream());
				out.flush();
				in = new ObjectInputStream(connection.getInputStream());
				
				//wait for the FileTransferMessage object. process it and send response back after processing the message
				
				try{
					Object messg = in.readObject();
					if(messg instanceof FileTransferMessage){
						FileTransferMessage outMessg = processMessage((FileTransferMessage)messg);
						out.writeObject(outMessg);
						out.flush();
					}
				}catch(Exception e){
					logger.error("Exception while sending/receving messages in the FileSender:"+e.getMessage());
					e.printStackTrace();
				}
			}
			
		}catch(Exception e){
			logger.error("Exception in the main try/catch of the FileSender:"+e.getMessage());
			e.printStackTrace();
		}finally{
			try{
				in.close();
				out.close();
				providerSocket.close();
			}catch(Exception e){
				logger.error("Exception while closing resources in FileSender:"+ e.getMessage());
				e.printStackTrace();
			}
		}		
	}
	
	
	
	/**
	 * 
	 * @param input
	 * @return
	 */
	private FileTransferMessage processMessage(FileTransferMessage input){
		FileTransferMessage output = null;
		FileInfo info = null;
		
		if(input != null && input.isError()){
			
			if(input.getMessageType() == Messages.CHUNK_REQUEST){
				/*
				 * Check if the file for which info is requested is present 
				 * in the list or not. if not present send error.
				 */
				output = new FileTransferMessage(Messages.CHUNK_RESPONSE);
				
				info = input.getFileInfo();
				if(info == null || !holder.getFileInfoList(true).contains(info)){
					output.setError(true);
					output.setErrorMessage("Invalid file requested. File :" + info.getFileName() + " is not present in the list of files available for download. ");
					
				}else{
					//Extract the byte[], make the ChunkData object and send.
					/*
					 * Get the chunk size, and num of chunks from the file info
					 * obj corresponding to the file whose chunk is requested.
					 * 
					 * if the chunk number being requested is beyond the num of chunks
					 * send back error.
					 * 
					 * once chunk number is validated, 
					 * get the filePtr position where it needs to seek in the random access file
					 * and read the length of bytes of chunk. if the chunk is the last chunk,
					 * then have to give the actual remaining length, instead of using the calculated chunk size.
					 * 
					 * 
					 */
					
					ChunkData data = input.getChunkData();
					long filePtr = 0;
					info = holder.getFileInfoList(false).get(holder.getFileInfoList(false).indexOf(info));
					long fileSize = info.getFileSize();
					filePtr = (data.getChunkNumber()-1)*info.getChunkSize();
					
					if(data == null || data.getChunkNumber() < 0 || data.getChunkNumber() > info.getNumChunks()){
						
					}else{
						//if numChunks is only 1, then just send the file.
						if(info.getNumChunks() == 1){
							//read the entire file into byte array and send
							
						}else{
							if(filePtr > fileSize){
								//error - calculation getting incorrect
							}else{
								//get random access file to seek here. read the bytes till the chunk
								//size. send the util class boolean if this is the last chunk.
								//if it is the last, then the util needs to read until the 
								//end of the file.
								
							}
						}
					}
					
					
				}
				
			}else{
				//put a log that the any other messages must not be sent to the server
				logger.warn("Invalid message type sent to the server:" + input.getMessageType() + " with the fileinfo: " + input.getFileInfo());
			}
			
		}
		return output;
	}	
}
